import bcrypt from "bcryptjs"
import jwt from "jsonwebtoken"

import userService from "../service/user.service.js"
const { getUserInfo } = userService
import errType from "../constant/err.type.js"
const {
  userRegisterError,
  userAlreadyExistsError,
  userNotExistError,
  invalidPasswordError,
  invalidTokenError,
  tokenExpiredError,
  passwordSameError,
} = errType

// 验证注册
const verifyRegister = async (ctx, next) => {
  const { user_name } = ctx.request.body
  try {
    const res = await getUserInfo({ user_name })
    if (res) {
      console.error("用户名已经存在", user_name)
      return ctx.app.emit("error", userAlreadyExistsError, ctx)
    }
  } catch (error) {
    console.error(error)
    return ctx.app.emit("error", userRegisterError, ctx)
  }
  await next()
}

// 密码加密
const cryptPassword = async (ctx, next) => {
  const { password } = ctx.request.body
  const salt = bcrypt.genSaltSync(10)
  const hash = bcrypt.hashSync(password, salt)
  ctx.request.body.password = hash
  await next()
}

// 验证登录
const verifyLogin = async (ctx, next) => {
  const { user_name, password } = ctx.request.body
  const res = await getUserInfo({ user_name })
  if (!res) {
    console.error("用户不存在", user_name)
    return ctx.app.emit("error", userNotExistError, ctx)
  }
  if (!bcrypt.compareSync(password, res.password)) {
    return ctx.app.emit("error", invalidPasswordError, ctx)
  }
  await next()
}

// 验证是否已经登录
const auth = async (ctx, next) => {
  const { authorization = "" } = ctx.request.header
  const token = authorization.replace("Bearer ", "")
  try {
    const user = jwt.verify(token, process.env.JWT_SECRET)
    ctx.state.user = user
  } catch (error) {
    switch (error.name) {
      case "TokenExpiredError":
        console.error("token已过期", error)
        return ctx.app.emit("error", tokenExpiredError, ctx)
      case "JsonWebTokenError":
        console.error("无效的token", error)
        return ctx.app.emit("error", invalidTokenError, ctx)
    }
  }
  await next()
}

// 验证修改密码
const verifyChangePassword = async (ctx, next) => {
  const { oldPassword, password } = ctx.request.body
  // 原密码与新密码是否相同
  if (oldPassword == password) return ctx.error(passwordSameError)
  const { user_name } = ctx.state.user
  const res = await getUserInfo({ user_name })
  // 原密码是否正确
  if (!bcrypt.compareSync(oldPassword, res.password)) {
    return ctx.error(invalidPasswordError)
  }
  await next()
}

export {
  verifyRegister,
  cryptPassword,
  verifyLogin,
  auth,
  verifyChangePassword,
}
